/*
 * Compresses standard input, which is assumed to have all whitespaces as
 * spaces, into standard output, which should have spaces replaced with
 * tabs where possible to compress the output.
 *
 * See also http://chris.agenteight.com/code/ as the source for doing
 * this. (I wanted to write my own version to see what would come out.)
 */
#include	<unistd.h>
#include	<stdio.h>

/* Tab stops are every 8 characters. */
#define	TABSTOPS	8

#define	BLOCKSIZE	(16*1024)

/*
 * Given a current line position and a target line position, output
 * spaces or tabs as necessary to bring us up to the target position.
 */
void
whiteout(int spos, int lpos)
{
	int	span;

	/* Do we have any work? */
	if (spos == -1)
		return;

	while (spos < lpos) {
		/* 'span' is the space a tab here would cover. */
		span = TABSTOPS - (spos % TABSTOPS);
		/*
		 * Tab output happens when we will cover more than one
		 * space and when we can without moving after the target
		 * position. Subtle: lpos is at the character *before* the
		 * non-whitespace character; we must thus cover up to and
		 * including it.
		 */
		if (span > 1 && lpos >= (span+spos)) {
			putchar('\t');
			spos += span;
		} else {
			putchar(' ');
			spos++;
		}
	}

	return;
}		

main(int argc, char **argv)
{
	char	ibuf[BLOCKSIZE];
	char	*iptr;
	int	res;
	int	lpos, spos, span;

	/*
	 * Indexing: lpos (and spos) are the character position in the
	 * current line. The first character in the line has ordinal
	 * position *zero*, not one, because the cycle of (mod TABSTOPS)
	 * arithmetic runs through zero.
	 */
	lpos = 0;
	spos = -1;
	while ((res = fread(ibuf, sizeof(char), sizeof(ibuf), stdin)) > 0) {
		for (iptr = ibuf; iptr < ibuf+res; iptr++) {
			if (*iptr == ' ') {
				/* Skip over whitespace, but track our
				   line position. */
				if (spos == -1)
					spos = lpos;
				lpos++;
			} else {
				/* Push out any necessary whitespace. */
				whiteout(spos, lpos);
				spos = -1;
				/* Now output the real character. */
				putchar(*iptr);
				/* reset line position on newlines */
				if (*iptr == '\n')
					lpos = 0;
				else
					lpos++;
			}
		}
	}
	/* We may have pending whitespace if stdin ends with whitespace
	   (such as a terminal line without a newline). Push it out. */
	whiteout(spos, lpos);
}
